package com.wtwd.campus.wx.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wtwd.campus.common.Constants;
import com.wtwd.campus.entity.WxCustomer;
import com.wtwd.campus.service.WxCustomerService;
import com.wtwd.campus.utils.DateUtils;
import com.wtwd.campus.utils.HttpclientUtil;
import com.wtwd.campus.utils.RequestClient;
import com.wtwd.campus.wx.service.WxUtilsService;
import com.wtwd.campus.wx.entity.PushMsgXCX;
import com.wtwd.campus.wx.entity.SimilarSort;
import com.wtwd.campus.wx.wxtemplate.WxTemplateEnum;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jeewx.api.core.exception.WexinReqException;
import org.jeewx.api.core.req.model.message.TemplateData;
import org.jeewx.api.core.req.model.message.TemplateMessageSendResult;
import org.jeewx.api.wxbase.wxtoken.JwTokenAPI;
import org.jeewx.api.wxsendmsg.JwSendTemplateMsgAPI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mjy
 * @date 2022/09/23
 * @description
 */
@Service
public class WxUtilsServiceImpl implements WxUtilsService {

    private static final Logger logger = LoggerFactory.getLogger(WxUtilsServiceImpl.class);

    //班级通知跳转查看详情的页面地址
    private static final String NOTIFICATION_DETAIL_URL = "https://campus.geelocks.com/wx/index.html?/#/pushDetails:";

    //资讯跳转查看详情的页面地址
    private static final String INFORMATION_DETAIL_URL = "https://campus.geelocks.com/wx/index.html?/#/pushDetails:";

    private static String jsApiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?";

    @Resource
    private WxCustomerService wxCustomerService;


    @Override
    public String getOpenId(String code, String appID, String appSecret, Integer type) throws Exception {
        String openid = null;
        if (type == GZH) {
            String openId = "openid";
            String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appID +
                    "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
            String res = RequestClient.createRequest().get(requestUrl).build().send();
            JSONObject json = JSON.parseObject(res);
            if (null != json.get(openId)) {
                openid = json.get(openId).toString();
            }
        } else {
            String openId = "openid";
            String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appID + "&secret=" + appSecret + "&js_code=" + code + "&grant_type=authorization_code";
            String res = RequestClient.createRequest().get(requestUrl).build().send();
            JSONObject json = JSON.parseObject(res);
            if (null != json.get(openId)) {
                openid = json.get(openId).toString();
            }
        }
        return openid;
    }

    @Override
    public Map<String, Object> getScanCodeCondition(String url, String appId, String appSecret) {
        //获取Access-Token
        String accessToken = "";
        Map<String, Object> params = new HashMap<>();
        params.put("corpid", appId);
        params.put("corpsecret", appSecret);
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet get = new HttpGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret);
        try {
            HttpResponse response = httpclient.execute(get);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String s = EntityUtils.toString(entity, "UTF-8");
                Map<String, Object> map = JSONObject.parseObject(s, Map.class);
                accessToken = (String) map.get("access_token");
            }
        } catch (IOException e) {
            e.printStackTrace();
            logger.info("获取Access_token失败");
        }
        //获取jsapiTicket
        String ticket = "";
        HttpGet get2 = new HttpGet(jsApiTicketUrl.concat("access_token=" + accessToken + "&type=jsapi"));
        try {
            CloseableHttpResponse response = httpclient.execute(get2);
            if (response.getEntity() != null) {
                String s = EntityUtils.toString(response.getEntity(), "UTF-8");
                Map<String, Object> map = JSONObject.parseObject(s, Map.class);
                ticket = (String) map.get("ticket");
            }
        } catch (IOException e) {
            e.printStackTrace();
            logger.info("获取jsApiTicket失败");
        }
        //获取signature
        String signature = "";
        String noncestr = UUID.randomUUID().toString();
        long time = System.currentTimeMillis();
        String str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + time + "&url=" + url;
        signature = SHA1(str);
        Map<String, Object> map = new HashMap<>();
        map.put("timestamp", time);
        map.put("noncestr", noncestr);
        map.put("appId", appId);
        map.put("signature", signature);
        return map;
    }

    @Override
    public TemplateMessageSendResult createOutFenceTemplate(String wxCustomerCode, String imei, String studentName, String classesName, String fence, double distance) {
        WxCustomer wxCustomer = wxCustomerService.getWxCustomerByCustomerCode(wxCustomerCode);
        if (wxCustomer == null) {
            return null;
        }
        if (wxCustomer.getType() == XCX) {//获取小程序模板
            String format = String.format("%.2f", distance);
            TemplateMessageSendResult template = new TemplateMessageSendResult();
            template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.OUT_OF_FENCE_TYPE).getTemplate());
            Map<String, TemplateData> data = new HashMap<>();
            TemplateData time = new TemplateData();
            time.setValue(DateUtils.format(new Date(), DateUtils.dateFormat4));
            data.put("date1", time);
            data.put("thing2", new TemplateData("尊敬的家长，您的小孩超出围栏。" + fence + format + "米", "#FF0000"));
            data.put("thing3", new TemplateData(studentName + "的设备", "#173177"));
            data.put("character_string4", new TemplateData(imei, "#173177"));
            data.put("thing6", new TemplateData("出围栏告警", "#173177"));
            template.setData(data);
            return template;
        }
        String format = String.format("%.2f", distance);
        TemplateMessageSendResult template = new TemplateMessageSendResult();
        template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.OUT_OF_FENCE_TYPE).getTemplate());
        Map<String, TemplateData> data = new HashMap<>();
        data.put("first", new TemplateData("尊敬的家长，您的小孩超出围栏。", "#173177"));
        data.put("keyword1", new TemplateData(classesName, "#FF0000"));
        data.put("keyword2", new TemplateData(studentName, "#FF0000"));
        data.put("keyword3", new TemplateData(fence + format + "米", "#FF0000"));
        data.put("remark", new TemplateData(" 为保证安全，请及时联系！", "#173177"));
        template.setData(data);
        return template;
    }

    @Override
    public TemplateMessageSendResult createEntryFenceTemplate(String wxCustomerCode, String imei, String studentName, String fence) {
        WxCustomer wxCustomer = wxCustomerService.getWxCustomerByCustomerCode(wxCustomerCode);
        if (wxCustomer == null) {
            return null;
        }
        if (wxCustomer.getType() == XCX) {//获取小程序模板
            TemplateMessageSendResult template = new TemplateMessageSendResult();
            template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.ENTRY_FENCE_TYPE).getTemplate());
            Map<String, TemplateData> data = new HashMap<>();
            TemplateData time = new TemplateData();
            time.setValue(DateUtils.format(new Date(), DateUtils.dateFormat4));
            data.put("date1", time);
            data.put("thing2", new TemplateData("尊敬的家长，您的小孩进入围栏" + fence, "#FF0000"));
            data.put("thing3", new TemplateData(studentName + "的设备", "#173177"));
            data.put("character_string4", new TemplateData(imei, "#173177"));
            data.put("thing6", new TemplateData("进围栏告警", "#173177"));
            template.setData(data);
            return template;
        }
        TemplateMessageSendResult template = new TemplateMessageSendResult();
        template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.ENTRY_FENCE_TYPE).getTemplate());
        Map<String, TemplateData> data = new HashMap<>();
        data.put("first", new TemplateData("尊敬的家长，您的小孩进入围栏。", "#173177"));
        data.put("keyword1", new TemplateData(imei, "#FF0000"));
        data.put("keyword2", new TemplateData(studentName, "#FF0000"));
        data.put("keyword3", new TemplateData(fence, "#FF0000"));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        data.put("keyword4", new TemplateData(sdf.format(new Date(System.currentTimeMillis())), "#FF0000"));
        data.put("remark", new TemplateData("感谢您使用", "#173177"));
        template.setData(data);
        return template;
    }

    @Override
    public TemplateMessageSendResult createNotificationTemplate(String wxCustomerCode, Integer id, String className, String title, String content) {
        WxCustomer wxCustomer = wxCustomerService.getWxCustomerByCustomerCode(wxCustomerCode);
        if (wxCustomer == null) {
            return null;
        }
        if (wxCustomer.getType() == XCX) {//获取小程序模板
            return null;
        }
        TemplateMessageSendResult template = new TemplateMessageSendResult();
        template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.INFORMATION_TEMPLATE_TYPE).getTemplate());
        Map<String, TemplateData> data = new HashMap<>();
        //设置具体推送信息
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timeStr = sdf.format(new Date(System.currentTimeMillis()));
        data.put("first", new TemplateData("尊敬的家长，您有一条".concat(className).concat("的班级通知。"), "#173177"));
        data.put("keyword2", new TemplateData(timeStr, "#FF0000"));
        content = content.length() > 12 ? content.substring(0, 12).concat("……") : content;
        data.put("keyword3", new TemplateData(content, "#FF0000"));
        data.put("remark", new TemplateData("点击查看详情", "#173177"));
        template.setData(data);
        template.setUrl(NOTIFICATION_DETAIL_URL.concat(String.valueOf(id)).concat(":").concat("1"));
        return template;
    }

    @Override
    public TemplateMessageSendResult createWarningTemplate(String wxCustomerCode, String imei, String stuName, Long time, String content, String tip) {
        WxCustomer wxCustomer = wxCustomerService.getWxCustomerByCustomerCode(wxCustomerCode);
        if (wxCustomer == null) {
            return null;
        }
        if (wxCustomer.getType() == XCX) {//获取小程序模板
            TemplateMessageSendResult template = new TemplateMessageSendResult();
            template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.ENTRY_FENCE_TYPE).getTemplate());
            Map<String, TemplateData> data = new HashMap<>();
            TemplateData timeData = new TemplateData();
            timeData.setValue(DateUtils.format(new Date(time), DateUtils.dateFormat4));
            data.put("date1", timeData);
            System.out.println("================================================================");
            data.put("thing2", new TemplateData("和开关开关苦尽甘来搞但是短时大大大大大大大大大", "#173177"));
            data.put("thing13", new TemplateData(stuName + "的设备", "#173177"));
            data.put("character_string4", new TemplateData(imei, "#173177"));
            data.put("thing6", new TemplateData(tip, "#173177"));
            template.setData(data);
            return template;
        }
        TemplateMessageSendResult template = new TemplateMessageSendResult();
        template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.INFORMATION_TEMPLATE_TYPE).getTemplate());
        Map<String, TemplateData> data = new HashMap<>();
        //设置具体推送信息
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timeStr = sdf.format(time);
        data.put("first", new TemplateData("尊敬的家长，".concat(tip), "#173177"));
        data.put("keyword1", new TemplateData(stuName.concat("家长"), "#FF0000"));
        data.put("keyword2", new TemplateData(timeStr, "#FF0000"));
        data.put("keyword3", new TemplateData(content, "#FF0000"));
        data.put("remark", new TemplateData("感谢您的使用", "#173177"));
        template.setData(data);
        template.setUrl("");
        return template;
    }

    @Override
    public TemplateMessageSendResult createInformationTemplate(String wxCustomerCode, Integer id, String type, String title, String content, String schoolName) {
        WxCustomer wxCustomer = wxCustomerService.getWxCustomerByCustomerCode(wxCustomerCode);
        if (wxCustomer == null) {
            return null;
        }
        if (wxCustomer.getType() == XCX) {//获取小程序模板
            return null;
        }
        TemplateMessageSendResult template = new TemplateMessageSendResult();
        template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.INFORMATION_TEMPLATE_TYPE).getTemplate());
        Map<String, TemplateData> data = new HashMap<>();
        //设置具体推送信息
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timeStr = sdf.format(new Date(System.currentTimeMillis()));
        data.put("first", new TemplateData("尊敬的家长，您有一条新的学校资讯。", "#173177"));
        data.put("keyword1", new TemplateData(schoolName.concat("全体家长"), "#FF0000"));
        data.put("keyword2", new TemplateData(timeStr, "#FF0000"));
        data.put("keyword3", new TemplateData(title, "#FF0000"));
        data.put("remark", new TemplateData("点击查看详情", "#173177"));
        template.setData(data);
        template.setUrl(INFORMATION_DETAIL_URL.concat(String.valueOf(id)).concat(":").concat("2"));
        return template;
    }

    @Override
    public TemplateMessageSendResult createSosRecordTemplate(String wxCustomerCode, JSONObject obj) {
        WxCustomer wxCustomer = wxCustomerService.getWxCustomerByCustomerCode(wxCustomerCode);
        if (wxCustomer == null) {
            return null;
        }
        if (wxCustomer.getType() == XCX) {//获取小程序模板
            TemplateMessageSendResult template = new TemplateMessageSendResult();
            template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.SOS_TEMPLATE_TYPE).getTemplate());
            Map<String, TemplateData> data = new HashMap<>();
            //设置具体推送信息
            String stuName = obj.getString("stuName");
            Long time = obj.getLong("time");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String schoolName = obj.getString("schoolName");
            String className = obj.getString("className");
            String gradeName = obj.getString("gradeName");
            String imei = obj.getString("imei");
            String address = obj.getString("address");
            String content = "告警地址:" + address;
            data.put("date1", new TemplateData(sdf.format(time), "#173177"));
            data.put("thing2", new TemplateData(content, "#FF0000"));
            data.put("thing3", new TemplateData(stuName + "的设备", "#173177"));
            data.put("character_string4", new TemplateData(imei, "#FF0000"));
            data.put("thing6", new TemplateData("sos告警", "#FF0000"));
            template.setData(data);
            return template;
        }
        TemplateMessageSendResult template = new TemplateMessageSendResult();
        template.setTemplate_id(WxTemplateEnum.getWxTemplateEnum(wxCustomerCode, WxTemplateEnum.SOS_TEMPLATE_TYPE).getTemplate());
        Map<String, TemplateData> data = new HashMap<>();
        //设置具体推送信息
        String stuName = obj.getString("stuName");
        Long time = obj.getLong("time");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String content = "尊敬的家长，您的孩子".concat(stuName).concat("在").concat(sdf.format(time)).concat("有一条SOS求救提醒！");
        String schoolName = obj.getString("schoolName");
        String className = obj.getString("className");
        String gradeName = obj.getString("gradeName");
        String address = obj.getString("address");
        data.put("first", new TemplateData(content, "#173177"));
        data.put("keyword1", new TemplateData(schoolName, "#FF0000"));
        data.put("keyword2", new TemplateData(gradeName.concat(className), "#FF0000"));
        data.put("keyword3", new TemplateData(stuName, "#FF0000"));
        data.put("keyword4", new TemplateData(sdf.format(time), "#FF0000"));
        data.put("keyword5", new TemplateData(address, "#FF0000"));
        data.put("remark", new TemplateData("请您关注，谢谢配合！", "#173177"));
        template.setData(data);
        return template;
    }

    @Override
    public boolean pushMsg(String wxCustomerCode, TemplateMessageSendResult template) {
        logger.info("pusWxMsg customerId={},", wxCustomerCode);
        WxCustomer wxCustomer = wxCustomerService.getWxCustomerByCustomerCode(wxCustomerCode);
        if (wxCustomer == null || StringUtils.isBlank(wxCustomer.getAppId()) || StringUtils.isBlank(wxCustomer.getAppSecret())) {
            return false;
        }
        boolean isSend = false;
        if (wxCustomer.getType() == XCX) {
            return pushMsgXCX(wxCustomer.getAppId(), wxCustomer.getAppSecret(), template);
        }
        try {
            String accessToken = getAccessToken(wxCustomer.getAppId(), wxCustomer.getAppSecret());
            logger.info("accessToken:{}", accessToken);
            String s = JwSendTemplateMsgAPI.sendTemplateMsg(accessToken, template);
            logger.info("发送微信客户={}消息模板成功:{}", wxCustomer.getCustomerName(), s);
            isSend = true;
        } catch (WexinReqException e) {
            logger.info("发送微信客户={}消息模板失败:{}", wxCustomer.getCustomerName());
        }
        return isSend;
    }

    @Override
    public boolean pushMsgXCX(String appId, String appSecret, TemplateMessageSendResult template) {
        try {
            String accessToken = getAccessToken(appId, appSecret);
            logger.info("accessToken:{}", accessToken);
            PushMsgXCX pushMsgXCX = new PushMsgXCX();
            pushMsgXCX.setTouser(template.getTouser());
            pushMsgXCX.setMiniprogram_state(PushMsgXCX.MIN_START_DEV);
            pushMsgXCX.setPage(template.getUrl());
            pushMsgXCX.setTemplate_id(template.getTemplate_id());
            pushMsgXCX.setData(template.getData());
            pushMsgXCX.setLang(PushMsgXCX.getLang());
            String jsondata = JSONObject.toJSONString(pushMsgXCX);
            JSONObject json = JSONObject.parseObject(jsondata);
            String s = HttpclientUtil.httpPost(XCX_PUSH_SUBSCRIBE_MESSAGE.concat(accessToken), json);
            logger.info("发送微信客户={}消息模板成功:{}", appId, s);
            return true;
        } catch (WexinReqException e) {
            logger.info("发送微信客户={}消息模板失败:{}", appId);
        }
        return false;
    }


    @Override
    public String getAccessToken(String appId, String appSecret) throws WexinReqException {
        String strToken = JwTokenAPI.getAccessToken(appId, appSecret);
        return strToken;
    }


    @Override
    public String getWxCustomerCode(List<String> codes, String deviceCode) {
        List<SimilarSort> similarSorts = similarSort(codes, deviceCode);
        if (similarSorts != null && similarSorts.size() > 0) {
            return similarSorts.get(0).getValue();
        }
        return null;
    }

    @Override
    public Map<String, String> getAccessTokenAndOpenId(String code, String appId, String appSecret, Integer customerType) throws Exception {
        Map<String, String> map = new HashMap<>();
        if (GZH.equals(customerType)) {
            String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
            String res = RequestClient.createRequest().get(requestUrl).build().send();
            JSONObject json = JSON.parseObject(res);
            logger.info("获取用户授权后的信息：" + res);
            if (null != json.get("openid") && null != json.get("access_token")) {
                map.put("accessToken", json.getString("access_token"));
                map.put("openId", json.getString("openid"));
            }
        } else {
            String openId = getOpenId(code, appId, appSecret, customerType);
            map.put("accessToken", "");
            map.put("openId", openId);
        }
        return map;
    }

    @Override
    public Map<String, Object> getUserInfo(String appId, String appSecret, Integer customerType, String accessToken, String openId) {
        String nickName = "";
        String headImg = "";
        if (GZH.equals(customerType)){
            String res = null;
            try {
                /* String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+accessToken+"&openid="+openId+"&lang=zh_CN";*/
                String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
                res = RequestClient.createRequest().get(requestUrl).build().send();
                logger.info("获取的微信用户的原始信息：".concat(res));
            } catch (Exception e) {
                e.printStackTrace();
            }
            JSONObject json = JSON.parseObject(res);
            if (null != json.get("nickname") && null != json.get("headimgurl")) {
                nickName = (String) json.get("nickname");
                headImg = (String) json.get("headimgurl");
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("name", nickName);
        map.put("headImg", headImg);
        return map;
    }


    /**
     * 进行SHA-1加密
     *
     * @param str
     * @return
     */
    public static String SHA1(String str) {
        MessageDigest digest = null;
        try {
            digest = MessageDigest.getInstance("SHA-1");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        digest.update(str.getBytes());
        byte[] digest1 = digest.digest();
        StringBuffer buffer = new StringBuffer();
        //字节数组转换成十六进制位
        for (int i = 0; i < digest1.length; i++) {
            String shaHex = Integer.toHexString(digest1[i] & 0xFF);
            if (shaHex.length() < 2) {
                buffer.append(0);
            }
            buffer.append(shaHex);
        }
        return buffer.toString();
    }


    // 返回相似度map
    public static List<SimilarSort> similarSort(List<String> arrList, String s) {
        List<SimilarSort> similarSorts = new ArrayList<>();
        arrList.forEach(str -> {
            int num = 0;
            if (str.contains(s) || s.contains(str)) {
                String[] split = str.split(s);
                for (int i = 0; i < split.length; i++) {
                    char[] chars = split[i].toCharArray();
                    for (char aChar : chars) {
                        num--;
                    }
                }
                // num 进行取反越大就说明越不相似
                num = -num;
            } else {
                num = -1;
            }
            if (num != -1) {
                SimilarSort similarSort = new SimilarSort();
                similarSort.setOrder(num);
                similarSort.setValue(str);
                similarSorts.add(similarSort);
            }
        });
        return similarSorts.stream().sorted(Comparator.comparing(SimilarSort::getOrder)).collect(Collectors.toList());
    }

}
